#pragma once
#include<vector>
#include<string>
#include <unordered_map>
#include <chrono>
#include <iostream>
#include "Tools.h"
using namespace std;

enum class CommandType :int {
    UNKNOWN,
    PING,
    ECHO,
    SET,
    GET,
    INFO,
    REPLCONF,
    PSYNC,
};

class Command {
public:
    CommandType command_type;
    vector<string> args;
    bool need_reply;
    Command(CommandType type, vector<string> args, bool need_reply = true) : command_type(type), args(move(args)) {}
    virtual string excute_command()=0 ;
    #ifdef DEBUG
    void show_info(){
        switch(command_type){
            case CommandType::PING:
                cout<<"PING";
                break;
            case CommandType::ECHO:
                cout<<"ECHO";
                break;
            case CommandType::SET:
                cout<<"SET";
                break;
            case CommandType::GET:
                cout<<"GET";
                break;
            case CommandType::INFO:
                cout<<"INFO";
                break;
            case CommandType::REPLCONF:
                cout<<"REPLCONF";
                break;
            case CommandType::PSYNC:
                cout<<"PSYNC";
                break;
            default:
                cout<<"UNKNOWN";
                break;
        };
        for(auto arg:args){
            cout<<arg<<" ";
        }
        cout<<endl;
        
    };
    #endif
};

class PingCommand : public Command {
public:
    PingCommand(vector<string> args, bool need_reply = true) : Command(CommandType::PING, args, need_reply) {

    }

    string excute_command() override{
        if(args.size()>=1){
            return simple_string(args.front());
        }else{
            return simple_string("PONG");
        }
    };
};


class EchoCommand : public Command {
public:
    EchoCommand(vector<string> args, bool need_reply = true) : Command(CommandType::ECHO, args, need_reply) {
    }

    string excute_command() override{
        if(args.size()>=1){
          return simple_string(args.front());
        }else{
          return "+\r\n";
        }
    };
};

class SetCommand : public Command {
public:
    SetCommand(vector<string> args, bool need_reply = true) : Command(CommandType::SET, args, need_reply) {
    }

    string excute_command() override;
};

class GetCommand : public Command {
public:
    GetCommand(vector<string> args, bool need_reply = true) : Command(CommandType::GET, args, need_reply) {

    }

    string excute_command() override;
};

class InfoCommand : public Command {
public:
    InfoCommand(vector<string> args, bool need_reply = true) : Command(CommandType::INFO, args, need_reply) {    }

    string excute_command() override;
};

class ReplConfCommand : public Command {
public:
    ReplConfCommand(vector<string> args, bool need_reply = true) : Command(CommandType::REPLCONF, args, need_reply) {
    }

    string excute_command() override{
        return simple_string("OK");
    };  
};

class PsyncCommand : public Command {
public:
    PsyncCommand(vector<string> args, bool need_reply = true) : Command(CommandType::PSYNC, args, need_reply) {
    }

    string excute_command() override;
};
